
package com.hlkj.pay.util;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.*;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author HlpayTeam
 * @date 2024/12/12 16:10
 */
public class CommonSignUtil {

    private static final Logger log = LoggerFactory.getLogger(CommonSignUtil.class);

    /**
     * 获取证书信息
     *
     * @param inputStream
     * @return
     */
    public static X509Certificate loadCertificate(InputStream inputStream) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
            String publicKeyBase64 = org.apache.commons.codec.binary.Base64.encodeBase64String(cert.getPublicKey().getEncoded());
            cert.checkValidity();
            return cert;
        }
        catch (CertificateExpiredException e) {
            throw new RuntimeException("证书已过期", e);
        }
        catch (CertificateNotYetValidException e) {
            throw new RuntimeException("证书尚未生效", e);
        }
        catch (CertificateException e) {
            e.printStackTrace();
            throw new RuntimeException("无效的证书", e);
        }
    }

    /**
     * 获取证书
     *
     * @param certFilePath
     * @return
     * @throws CertificateException
     * @throws NoSuchProviderException
     * @throws IOException
     */
    public static X509Certificate getX509Certificate(String certFilePath) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
            byte[] readAllBytes = Files.readAllBytes(Paths.get(certFilePath));
            String fileContent = new String(readAllBytes);
            if ("-----BEGIN CERTIFICATE-----".indexOf(fileContent) < 0) {
                fileContent = "-----BEGIN CERTIFICATE-----\n" + fileContent + "\n-----END CERTIFICATE-----";
            }
            InputStream is = new ByteArrayInputStream(fileContent.getBytes());
            return (X509Certificate) cf.generateCertificate(is);
        }
        catch (CertificateExpiredException e) {
            throw new RuntimeException("证书已过期", e);
        }
        catch (CertificateNotYetValidException e) {
            throw new RuntimeException("证书尚未生效", e);
        }
        catch (CertificateException e) {
            e.printStackTrace();
            throw new RuntimeException("无效的证书", e);
        }
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("无效的证书", e);
        }
        catch (NoSuchProviderException e) {
            e.printStackTrace();
            throw new RuntimeException("无效的证书", e);
        }
    }

    /**
     * 签名验证
     *
     * @param notifyCertPath
     * @param body
     * @param signature
     * @return
     */
    public static boolean verify(String notifyCertPath, String body, String signature) throws Exception {
        log.info("回调签名验证 notifyCertPath:{},body:{},signature:{}", notifyCertPath, body, signature);
        X509Certificate lklCertificate = loadCertificate(new FileInputStream(new File(notifyCertPath)));
        return verify(lklCertificate, body.getBytes("utf-8"), signature);
    }

    /**
     * 签名验证
     *
     * @param certificate
     * @param message
     * @param signature
     * @return
     */
    private static boolean verify(X509Certificate certificate, byte[] message, String signature) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initVerify(certificate);
            sign.update(message);
            byte[] signatureB = org.apache.commons.codec.binary.Base64.decodeBase64(signature);
            return sign.verify(signatureB);
        }
        catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
        }
        catch (SignatureException e) {
            e.printStackTrace();
            throw new RuntimeException("签名验证过程发生了错误", e);
        }
        catch (InvalidKeyException e) {
            e.printStackTrace();
            throw new RuntimeException("无效的证书", e);
        }
    }
}
